/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.registration.gui.security;

/**
 *
 * @author Luca
 */
//package org.primefaces.showcase.view.data;
import it.polimi.registration.business.security.boundary.BadWeatherManager;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

import org.primefaces.event.ScheduleEntryMoveEvent;
import org.primefaces.event.ScheduleEntryResizeEvent;
import org.primefaces.event.SelectEvent;
import org.primefaces.model.DefaultScheduleEvent;
import org.primefaces.model.DefaultScheduleModel;
import org.primefaces.model.LazyScheduleModel;
import org.primefaces.model.ScheduleEvent;
import org.primefaces.model.ScheduleModel;

import it.polimi.registration.business.security.boundary.EventManager;
import it.polimi.registration.business.security.boundary.ForecastManager;
import it.polimi.registration.business.security.boundary.UsersManager;
import it.polimi.registration.business.security.entity.BadWeatherNotification;
import it.polimi.registration.business.security.entity.Event;
import it.polimi.registration.business.security.entity.MyForecast;
import it.polimi.registration.business.security.weather.OwmClient;
import it.polimi.registration.business.security.weather.WeatherStatusResponse;
import static it.polimi.registration.gui.security.ForecastBean.upToDate;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateful;
import net.aksingh.java.api.owm.DailyForecastData;
import net.aksingh.java.api.owm.DailyForecastData.Forecast;
import net.aksingh.java.api.owm.OpenWeatherMap;
import org.codehaus.jettison.json.JSONException;

@ManagedBean
@ViewScoped
@Stateful
public class ScheduleViewBean implements Serializable {

    private ScheduleModel eventModel;

    @EJB
    private EventManager evm;

    @EJB
    private UsersManager um;
    @EJB
    private ForecastManager fm;
    
    @EJB
    private BadWeatherManager bwm;

    List<Event> eventToCheck = new ArrayList<>();
    List<MyForecast> myforecastlist = new ArrayList<>();
    private MyForecast myforecast;
    Date today = new Date();

    @PostConstruct
    public void init() {
        eventModel = new DefaultScheduleModel();

        //checkEventWeather();
        sendNotifications();
        loadCalendar();

    }

    public Date getRandomDate(Date base) {
        Calendar date = Calendar.getInstance();
        date.setTime(base);
        date.add(Calendar.DATE, ((int) (Math.random() * 30)) + 1);    //set random day of month

        return date.getTime();
    }

    public Date getInitialDate() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(calendar.get(Calendar.YEAR), Calendar.FEBRUARY, calendar.get(Calendar.DATE), 0, 0, 0);

        return calendar.getTime();
    }

    private Calendar today() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DATE), 0, 0, 0);

        return calendar;
    }

    private Date previousDay8Pm() {
        Calendar t = (Calendar) today().clone();
        t.set(Calendar.AM_PM, Calendar.PM);
        t.set(Calendar.DATE, t.get(Calendar.DATE) - 1);
        t.set(Calendar.HOUR, 8);

        return t.getTime();
    }

    private Date previousDay11Pm() {
        Calendar t = (Calendar) today().clone();
        t.set(Calendar.AM_PM, Calendar.PM);
        t.set(Calendar.DATE, t.get(Calendar.DATE) - 1);
        t.set(Calendar.HOUR, 11);

        return t.getTime();
    }

    private Date today1Pm() {
        Calendar t = (Calendar) today().clone();
        t.set(Calendar.AM_PM, Calendar.PM);
        t.set(Calendar.HOUR, 1);

        return t.getTime();
    }

    private Date theDayAfter3Pm() {
        Calendar t = (Calendar) today().clone();
        t.set(Calendar.DATE, t.get(Calendar.DATE) + 2);
        t.set(Calendar.AM_PM, Calendar.PM);
        t.set(Calendar.HOUR, 3);

        return t.getTime();
    }

    private Date today6Pm() {
        Calendar t = (Calendar) today().clone();
        t.set(Calendar.AM_PM, Calendar.PM);
        t.set(Calendar.HOUR, 6);

        return t.getTime();
    }

    private Date nextDay9Am() {
        Calendar t = (Calendar) today().clone();
        t.set(Calendar.AM_PM, Calendar.AM);
        t.set(Calendar.DATE, t.get(Calendar.DATE) + 1);
        t.set(Calendar.HOUR, 9);

        return t.getTime();
    }

    private Date nextDay11Am() {
        Calendar t = (Calendar) today().clone();
        t.set(Calendar.AM_PM, Calendar.AM);
        t.set(Calendar.DATE, t.get(Calendar.DATE) + 1);
        t.set(Calendar.HOUR, 11);

        return t.getTime();
    }

    private Date fourDaysLater3pm() {
        Calendar t = (Calendar) today().clone();
        t.set(Calendar.AM_PM, Calendar.PM);
        t.set(Calendar.DATE, t.get(Calendar.DATE) + 4);
        t.set(Calendar.HOUR, 3);

        return t.getTime();
    }

    public void loadCalendar() {
        List<Event> listCalendar = getEvm().loadCalendar(getUm().getLoggedUsers());
        eventModel = new DefaultScheduleModel();
        for (Event listCalendar1 : listCalendar) {
            DefaultScheduleEvent temp;
            if (!fm.getForecastOfEvent(listCalendar1).isEmpty()) {
                temp = new DefaultScheduleEvent(listCalendar1.getTitle() + " *" + fm.getForecastOfEvent(listCalendar1).get(0).getDescription() + " *", listCalendar1.getStartDate(), listCalendar1.getEndDate(), "");
            } else {
                temp = new DefaultScheduleEvent(listCalendar1.getTitle() + " * No Forecast *", listCalendar1.getStartDate(), listCalendar1.getEndDate(), "");
            }
            temp.setDescription(listCalendar1.getId().toString());
            eventModel.addEvent(temp);
        }

    }
    
    public void loadCalendar(Event e){
        eventModel = new DefaultScheduleModel();
        DefaultScheduleEvent temp;
        temp = new DefaultScheduleEvent(e.getTitle(), e.getStartDate(), e.getEndDate(), "");
        eventModel.addEvent(temp);
    }

    public ScheduleModel getEventModel() {
        return eventModel;
    }

    public void setEvent(Event event) {
        System.out.println("SET");
        //this.event = event;
    }

    public void onEventMove(ScheduleEntryMoveEvent event) {
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Event moved", "Day delta:" + event.getDayDelta() + ", Minute delta:" + event.getMinuteDelta());

        addMessage(message);
    }

    public void onEventResize(ScheduleEntryResizeEvent event) {
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Event resized", "Day delta:" + event.getDayDelta() + ", Minute delta:" + event.getMinuteDelta());

        addMessage(message);
    }

    private void addMessage(FacesMessage message) {
        FacesContext.getCurrentInstance().addMessage(null, message);
    }

    /**
     * @return the evm
     */
    public EventManager getEvm() {
        return evm;
    }

    /**
     * @param evm the evm to set
     */
    public void setEvm(EventManager evm) {
        this.evm = evm;
    }

    /**
     * @return the um
     */
    public UsersManager getUm() {
        return um;
    }

    /**
     * @param um the um to set
     */
    public void setUm(UsersManager um) {
        this.um = um;
    }

    public void checkEventWeather() {
        String place;
        byte forecastDays;
        DailyForecastData.Forecast w = new DailyForecastData.Forecast();
        myforecastlist = fm.getAllForecast();
        eventToCheck = evm.getEventWithPreference();
        Boolean isNew;
        for (int i = 0; i < eventToCheck.size(); i++) {
            place = eventToCheck.get(i).getLocation().getCity();
            isNew = newForecast(eventToCheck.get(i), myforecastlist);
            forecastDays = upToDate(eventToCheck.get(i).getEndDate());
            w = getForecastForAnEvent(place, forecastDays);
            if (isNew) {
                
                if (!w.getWeather_List().isEmpty()) {
                    myforecast = getMyForecast();
                    myforecast.setDescription(w.getWeather_List().get(0).getWeatherDescription());
                    myforecast.setDate(eventToCheck.get(i).getEndDate());
                    myforecast.setLocation(eventToCheck.get(i).getLocation());
                    fm.save(myforecast);
                    eventToCheck.get(i).setMyforecast(myforecast);
                } else {
                    myforecast = getMyForecast();
                    myforecast.setDescription("Weather not aviable");
                    myforecast.setDate(eventToCheck.get(i).getEndDate());
                    myforecast.setLocation(eventToCheck.get(i).getLocation());
                    fm.save(myforecast);
                    eventToCheck.get(i).setMyforecast(myforecast);
                }
            } else {
                if (!w.getWeather_List().isEmpty()) {
                    myforecast = getMyForecast();
                    myforecast.setDescription(w.getWeather_List().get(0).getWeatherDescription());
                    myforecast.setDate(eventToCheck.get(i).getEndDate());
                    myforecast.setLocation(eventToCheck.get(i).getLocation());
                    fm.updateForecast(eventToCheck.get(i), myforecast.getDescription());
                    eventToCheck.get(i).setMyforecast(myforecast);
            }}

        }

    }

    public void checkOneEventWeather(Event event) {
        String place;
        byte forecastDays;
        DailyForecastData.Forecast w = new DailyForecastData.Forecast();
        place = event.getLocation().getCity();
        forecastDays = upToDate(event.getEndDate());
        w = getForecastForAnEvent(place, forecastDays);

        myforecast = new MyForecast();
        myforecast.setDescription(w.getWeather_List().get(0).getWeatherDescription());
        myforecast.setDate(event.getEndDate());
        myforecast.setLocation(event.getLocation());
        fm.save(myforecast);
    }

    public DailyForecastData.Forecast getForecastForAnEvent(String place, byte forecastDays) {

        try {
            OpenWeatherMap owm = new OpenWeatherMap(OpenWeatherMap.OWM_URL.PARAMETER_UNITS_VALUE_METRIC, "");

            DailyForecastData dfd = owm.dailyForecastByCityName(place, forecastDays);
            if (dfd.getForecast_List() != null) {
                DailyForecastData.Forecast forecast = dfd.getForecast_List().get(0);
                System.out.println(forecast.getWeather_List().get(0).getWeatherName());
                return forecast;
            } else {
                return new DailyForecastData.Forecast();
            }
        } catch (IOException ex) {
            //Logger.getLogger(ForecastBean.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Forecast not aviable");
            return new DailyForecastData.Forecast();
        } catch (org.json.JSONException ex) {
            Logger.getLogger(ForecastBean.class.getName()).log(Level.SEVERE, null, ex);
            return new DailyForecastData.Forecast();
        }
    }

    public Boolean newForecast(Event e, List<MyForecast> f) {
        Boolean b = true;
        for (MyForecast f1 : f) {
            if (giornoUguale(f1.getDate(), e.getEndDate()) && f1.getLocation().getCity().equals(e.getLocation().getCity())) {
                b = false;
            }
        }
        return b;
    }

    public MyForecast getMyForecast() {
        if (myforecast == null) {
            myforecast = new MyForecast();
        }

        return myforecast;
    }

    public Boolean giornoUguale(Date d1, Date d2) {

        if (d1.getDate() == d2.getDay() && d1.getMonth() == d2.getMonth() && d1.getYear() == d2.getYear()) {
            return true;
        } else {
            return false;
        }
    }
    
    

    public void sendNotifications() {
        eventToCheck = evm.getEventWithPreference();
        byte day = 1;
        for (int i=0; i<eventToCheck.size(); i++) {
            if((upToDate(eventToCheck.get(i).getStartDate())==day) && (eventToCheck.get(i).getMyforecast().getDescription().contains("rain")) ){
                BadWeatherNotification bwn = new BadWeatherNotification();
                bwn.setMessage("rain");
                bwn.setSeen(Boolean.FALSE);
                bwn.setReferredEvent(eventToCheck.get(i));
                bwm.save(bwn);
            }
        }

    }

}
